package com.platform.core.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.google.common.base.Strings;
import com.platform.core.repository.SysLogRepository;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.Predicate;
import com.platform.comm.dto.DtoMapper;
import com.platform.comm.enums.YnEnum;
import com.platform.comm.jwt.TokenInfoUtil;
import com.platform.dto.LogQo;
import com.platform.dto.UserQo;
import com.platform.core.entity.QSysLog;
import com.platform.core.entity.QSysUser;
import com.platform.core.entity.SysLog;
import com.platform.enums.CommFlagType;
import com.platform.enums.OptLogType;
import com.platform.core.service.SysLogService;
import com.platform.core.service.SysUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.querydsl.QSort;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.MultiValueMap;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Description: 日志-Service接口实现类
 *
 * @author libin Created on 2019/7/19
 **/
@Service
public class SysLogServiceImpl extends BaseEntityBizImpl<SysLogRepository, SysLog> implements SysLogService {
    private final QSysLog qSysLog = QSysLog.sysLog;
    private final QSysUser qSysUser = QSysUser.sysUser;
    private final DtoMapper dtoMapper;
    private final TokenInfoUtil tokenInfoUtil;
    private final SysUserService sysUserService;

    public SysLogServiceImpl(SysLogRepository baseRepository, DtoMapper dtoMapper, TokenInfoUtil tokenInfoUtil,
                             SysUserService sysUserService) {
        super(baseRepository);
        this.dtoMapper = dtoMapper;
        this.tokenInfoUtil = tokenInfoUtil;
        this.sysUserService = sysUserService;
    }

    @Async
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void create(LogQo logQo) {
        SysLog entity = dtoMapper.map(logQo, SysLog.class);
        saveEntity(entity);
    }

    @Override
    public Page<LogQo> queryGatherOptLogs(Predicate predicate, Pageable pageable, Map<String, String> parameters) {
        if (pageable.getSort().isUnsorted()) {
            pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), QSort.by(qSysLog.operateDate.desc()));
        }
        BooleanBuilder builder = new BooleanBuilder(predicate);
        String name = parameters.get("operateName");
        String type = parameters.get("type");
        String id = parameters.get("id");
        if (!Strings.isNullOrEmpty(name)) {
            builder.and(qSysLog.operateName.like("%" + name + "%"));
        }
        // WRONG_ ; QUE_; TOAUDIT_;
        if (!Strings.isNullOrEmpty(type)){
            builder.and(qSysLog.type.like(type+"%"));
        }
        String start = parameters.get("operateDateStart");
        if (!Strings.isNullOrEmpty(start)) {
            builder.and(qSysLog.operateDate.after(LocalDateTime.parse(start)));
        }
        String end = parameters.get("operateDateEnd");
        if (!Strings.isNullOrEmpty(end)) {
            builder.and(qSysLog.operateDate.before(LocalDateTime.parse(end)));
        }
        if (!Strings.isNullOrEmpty(id)) {
            builder.and(qSysLog.id.eq(id));
        }
        builder.and(qSysLog.moduleName.like("采报大厅"+"%"));
        builder.and(qSysLog.userId.eq(tokenInfoUtil.getUserId()));
        Page<SysLog> page = queryByPage(builder, pageable);
        return page.map(entity -> {
                    LogQo logQo = dtoMapper.map(entity, LogQo.class);
                    UserQo userQo = sysUserService.getByUserId(logQo.getUserId());
                    logQo.setUserName(userQo.getRealName());
                    logQo.setType(OptLogType.getTextByCode(logQo.getType()));
                    return logQo;
                }
        );
    }
    @Override
    public Page<LogQo> queryLogs(Predicate predicate, Pageable pageable, MultiValueMap<String, String> parameters) {
        if (pageable.getSort().isUnsorted()) {
            pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), QSort.by(qSysLog.operateDate.desc()));
        }
        BooleanBuilder builder = new BooleanBuilder(predicate);
        String name = parameters.getFirst("operateName");
        if (!Strings.isNullOrEmpty(name)) {
            builder.and(qSysLog.operateName.contains(name));
        }
        String loginName = parameters.getFirst("loginName");
        if (!Strings.isNullOrEmpty(loginName)) {
            builder.and(qSysLog.loginName.eq(loginName));
        }
        String moduleName = parameters.getFirst("moduleName");
        if (StringUtils.isNotBlank(moduleName)) {
            builder.and(qSysLog.moduleName.contains( moduleName));
        }
        builder.and(qSysLog.moduleName.notLike("%" + "采报大厅" + "%"));
        String start = parameters.getFirst("operateDateStart");
        if (!Strings.isNullOrEmpty(start)) {
            builder.and(qSysLog.operateDate.after(LocalDateTime.parse(start)));
        }
        String end = parameters.getFirst("operateDateEnd");
        if (!Strings.isNullOrEmpty(end)) {
            builder.and(qSysLog.operateDate.before(LocalDateTime.parse(end)));
        }
        Page<SysLog> page = queryByPage(builder, pageable);
        return page.map(entity -> {
                    LogQo logQo = dtoMapper.map(entity, LogQo.class);
                    UserQo userQo = sysUserService.getByUserId(logQo.getUserId());
                    logQo.setUserName(userQo.getRealName());
                    return logQo;
                }
        );
    }

    @Override
    public List<Map<String, Object>> querySysLogInfos(List<String> departIds) {
        List<Map<String, Object>> retList = new ArrayList<>();
        String logController = "登录管理";
        BooleanBuilder base = new BooleanBuilder(qSysLog.moduleName.eq(logController));
        List<Tuple> tuples = repository.findAll(base, jpqlQuery ->
                        jpqlQuery.leftJoin(qSysUser).on(qSysUser.id.eq(qSysLog.userId))
                                .where(qSysUser.delFlag.eq(YnEnum.N).and(qSysUser.status.eq(CommFlagType.Enabled)))
                , qSysLog, qSysUser.departId);
        tuples.forEach(tuple -> {
            SysLog sysLog = tuple.get(qSysLog);
            String departId = tuple.get(qSysUser.departId);
            if (departIds.contains(departId) && Objects.nonNull(sysLog) && sysLog.getSuccess().equals(YnEnum.Y)) {
                Map<String, Object> tMap = new HashMap<>(16);
                tMap.put(departId, sysLog.getOperateDate());
                retList.add(tMap);
            }
        });
        return retList;
    }

    @Override
    public LogQo queryLogById(String id){
        SysLog sysLog = queryOne(qSysLog.requestUrl.eq(id)).orElse(new SysLog());
        return dtoMapper.map(sysLog, LogQo.class);
    }

    @Override
    public LocalDateTime queryUserLastLoginTime() {

        String logController = "登录管理";
        List<Tuple> iterable = repository.findAll(qSysLog.userId.eq(tokenInfoUtil.getUser().getId()).and(qSysLog.moduleName.eq(logController)),Sort.by(Sort.Direction.DESC,"operateDate"), qSysLog.operateDate);
        if (CollUtil.isEmpty(iterable)){
            return null;
        }else{
            return iterable.get(0).get(qSysLog.operateDate);
        }
    }
}
